package com.audaque.springboot.foshanupload.core.config;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import com.alibaba.ttl.threadpool.TtlExecutors;
import com.audaque.springboot.foshanupload.core.handler.RejectedExecutionHandlerImpl;
import com.audaque.springboot.foshanupload.core.properties.ThreadProperties;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.annotation.Resource;
import java.util.concurrent.*;

/**
 * @author zgb
 * @desc ...
 * @date 2021-05-25 16:24:33
 */
@EnableAsync
@Slf4j
@Configuration
public class ThreadPoolConfig {
    @Resource
    private ThreadProperties threadProperties;


    /**
     * 上下文安全的线程池
     *
     * @return
     */
    @Bean
    public Executor ttlExecutor() {
        return TtlExecutors.getTtlExecutor(this.threadPoolExecutor());
    }

    /**
     * 给显式调用不分读写不分业务的异步使用
     *
     * @return
     */
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {
        Boolean singleThread = threadProperties.getSingleThread();
        int availableProcessors = 0;
        int availableProcessorsMultipleResult = 0;
        if (singleThread) {
            availableProcessors = 1;
            availableProcessorsMultipleResult = 1;
        } else {
            availableProcessors = threadProperties.getAvailableProcessors();
            availableProcessorsMultipleResult = threadProperties.getAvailableProcessorsMultipleResult();
        }


        int availableProcessorsQueueSize = threadProperties.getAvailableProcessorsQueueSize();
        int availableProcessorsAwaitTerminationSeconds = threadProperties.getAvailableProcessorsAwaitTerminationSeconds();
        log.debug("availableProcessors:" + availableProcessors);


        //自定义线程工厂
        ThreadFactory threadFactory = new ThreadFactoryBuilder()
                .setNamePrefix("scheduledExecutorService-thread-")
                //自定义线程内异常处理器：如果想要我们自定义的异常处理器生效，要使用ThreadPoolExecutor的execute()方法，而不再是submit()方法。
                .setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread t, Throwable e) {
                        log.error(" 当前线程名称    : " + t.getName());
                        log.error(" 线程内异常 string   : " + e.toString());
                        log.error(" 线程内异常 messae   : " + e.getMessage());
                    }
                })
                /*.setThreadFactory(new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r);
                        thread.setName(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                        //自定义线程内异常处理器
                        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                            @Override
                            public void uncaughtException(Thread t, Throwable e) {
                                log.error(" 当前线程名称    : " + t.getName());
                                log.error(" 线程内异常 string   : " + e.toString());
                                log.error(" 线程内异常 messae   : " + e.getMessage());
                            }
                        });
                        return thread;
                    }
                })*/
                .build();
        //自定义线程池拒绝策略
        RejectedExecutionHandlerImpl rejectedExecutionHandlerImpl = new RejectedExecutionHandlerImpl() ;
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(availableProcessors, availableProcessorsMultipleResult, availableProcessorsAwaitTerminationSeconds, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(availableProcessorsQueueSize), threadFactory, rejectedExecutionHandlerImpl);

        return threadPoolExecutor;
    }


    /**
     * 定时任务池
     * public  class  ScheduleExecutorTest  {
     * <p>
     * public  static  void  main(String[]  args)  {
     * ScheduledExecutorService  scheduledExecutorService  =  Executors.newScheduledThreadPool(5);
     * scheduledExecutorService.scheduleAtFixedRate(()  ->  {
     * System.out.println("doSomething");
     * },1000,1000,  TimeUnit.MILLISECONDS);
     * }
     * }
     * 调用ScheduledExecutorService类的scheduleAtFixedRate方法实现周期性任务，每隔1秒钟执行一次，每次延迟1秒再执行。
     *
     * @return
     */
    @Bean
    public ScheduledExecutorService scheduledExecutorService() {
        Boolean singleThread = threadProperties.getSingleThread();
        int availableProcessors = 0;
        if (singleThread) {
            availableProcessors = 1;
        } else {
            availableProcessors = threadProperties.getAvailableProcessors();
        }

        log.debug("availableProcessors:" + availableProcessors);

        //线程工厂
        ThreadFactory threadFactory = new ThreadFactoryBuilder()
                .setNamePrefix("scheduledExecutorService-thread-")
                //自定义线程内异常处理器：如果想要我们自定义的异常处理器生效，要使用ThreadPoolExecutor的execute()方法，而不再是submit()方法。
                .setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread t, Throwable e) {
                        log.error(" 当前线程名称    : " + t.getName());
                        log.error(" 线程内异常 string   : " + e.toString());
                        log.error(" 线程内异常 messae   : " + e.getMessage());
                    }
                })
                /*.setThreadFactory(new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r);
                        thread.setName(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                        //自定义线程内异常处理器
                        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                            @Override
                            public void uncaughtException(Thread t, Throwable e) {
                                log.error(" 当前线程名称    : " + t.getName());
                                log.error(" 线程内异常 string   : " + e.toString());
                                log.error(" 线程内异常 messae   : " + e.getMessage());
                            }
                        });
                        return thread;
                    }
                })*/
                .build();


        //创建线程池
        /**
         * Executors 返回线程池对象的弊端如下：
         * 　　FixedThreadPool 和 SingleThreadExecutor ：
         * 　　队列长度为Integer.MAX_VALUE，可能堆积大量的请求，从而导致OOM。
         *
         * 　　CachedThreadPool 和 ScheduledThreadPool ：
         * 　　最大线程数为Integer.MAX_VALUE ，可能会创建大量线程，从而导致OOM。
         *
         * 	xss代表线程栈大小，默认1m,可设置为128k，那么栈内存/128k=最大线程数=最大队列长度
         */
        return Executors.newScheduledThreadPool(availableProcessors, threadFactory);
    }

    /**
     * @return
     * @Async任务池 实现AsyncConfigurer接口+@EnableAsync+ThreadPoolTaskExecutor开启线程池，在需要使用异步调用的方法上使用@Async，调用该方法时就会从线程池取出空闲线程去执行该方法
     * 目的：减少线程开启和关闭的开资
     */
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        Boolean singleThread = threadProperties.getSingleThread();
        int availableProcessors = 0;
        int availableProcessorsMultipleResult = 0;
        if (singleThread) {
            availableProcessors = 1;
            availableProcessorsMultipleResult = 1;
        } else {
            availableProcessors = threadProperties.getAvailableProcessors();
            availableProcessorsMultipleResult = threadProperties.getAvailableProcessorsMultipleResult();
        }


        int availableProcessorsQueueSize = threadProperties.getAvailableProcessorsQueueSize();
        int availableProcessorsAwaitTerminationSeconds = threadProperties.getAvailableProcessorsAwaitTerminationSeconds();
        //int availableProcessors = systemPropertiesDynamic.getAvailableProcessors();
        log.debug("availableProcessors:" + availableProcessors);
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心池的大小（即线程池中的线程数目大于这个参数时，提交的任务会被放进任务缓存队列）
        executor.setCorePoolSize(availableProcessors);
        // 线程池最大能容忍的线程数
        executor.setMaxPoolSize(availableProcessorsMultipleResult);
        // 任务缓存队列，用来存放等待执行的任务
        executor.setQueueCapacity(availableProcessorsQueueSize);
        //用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean，这样这些异步任务的销毁就会先于Redis线程池的销毁
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 线程池维护线程所允许的空闲时间
        executor.setAwaitTerminationSeconds(availableProcessorsAwaitTerminationSeconds);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(availableProcessorsAwaitTerminationSeconds);
        executor.setThreadNamePrefix("threadPoolTaskExecutor-thread-");
        executor.setThreadGroupName("threadPoolTaskExecutor-group-");
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 所有任务结束后关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.initialize();
        return executor;
    }


}
